function createElement (type, props, ...children) {
  delete props.__source
  return {
    type,
    props: {
      ...props,
      children: children.map(
        child => typeof child === 'object' ? child : createTextElement(child)
      )
    }
  }
}

function createTextElement (text) {
  return {
    type: 'TEXT',
    props: {
      nodeValue: text,
      children: [],
    }
  }
}

function createDom (vdom) {
  // 创建Dom 
  const dom = vdom.type === 'TEXT'
    ? document.createTextNode("")
    : document.createElement(vdom.type)
  updateDom(dom, {}, vdom.props)
  // Object.keys(vdom.props).forEach(name => {
  //   if (name !== 'children') {
  //     // @todo: 属性判断，事件处理
  //     dom[name] = vdom.props[name]
  //   }
  // })
  return dom
}

function updateDom (dom, preProps, nextProps) {
  /**
   * 1. 规避 children 属性
   * 2. 老得存在，取消
   * 3. 新的存在，新增， 
   */

  // @todo 兼容性问题
  Object.keys(preProps)
    .filter(name => name !== 'children')
    .filter(name => !(name in nextProps))
    .forEach(name => {
      if (name.slice(0, 2) === 'on') {
        // onclick => chick
        dom.removeEventListener(name.slice(2).toLowerCase(), preProps[name], false)
      } else {
        dom[name] = ''
      }
    })

  Object.keys(nextProps)
    .filter(name => name !== 'children')
    .forEach(name => {
      if (name.slice(0, 2) === 'on') {
        // onclick => chick
        dom.addEventListener(name.slice(2).toLowerCase(), preProps[name], false)
      } else {
        dom[name] = nextProps[name]
      }
    })
}

function render (vdom, container) {
  // // 我们先在页面上渲染处 dom 的 json 结构
  // container.innerHTML = `<pre>${JSON.stringify(vdom, null, 2)}</pre>`

  // const dom = vdom.type === "TEXT" ? document.createTextNode("") : document.createElement(vdom.type)
  // // 设置属性
  // Object.keys(vdom.props).forEach(name => {
  //   if (name !== 'children') {
  //     // @todo: 属性判断，事件处理
  //     dom[name] = vdom.props[name]
  //   }
  // })

  // // 递归渲染的子元素
  // vdom.props.children.forEach(child => render(child, dom))

  // container.appendChild(dom)

  wipRoot = {
    dom: container,
    props: {
      children: [vdom]
    },
    base: currentRoot,
  }
  deletions = []
  nextUnitOfWork = wipRoot
}

function commitRoot () {
  deletions.forEach(commitWorker)
  commitWorker(wipRoot.child)
  currentRoot = wipRoot
  wipRoot = null
}

function commitWorker (fiber) {
  if (!fiber) {
    return
  }
  // const domParent = fiber.parent.dom
  // domParent.appendChild(fiber.dom)
  let domParentFiber = fiber.parent
  while (!domParentFiber.dom) {
    domParentFiber = domParentFiber.parent
  }
  const domParent = domParentFiber.dom
  if (fiber.effectTag === "PLACEMENT" && fiber.dom !== null) {
    domParent.appendChild(fiber.dom)
  } else if (fiber.effectTag === 'DELETION') {
    commitDeletion(fiber, domParent)
    // domParent.removeChild(fiber.dom)
  } else if (fiber.effectTag === 'UPDATE' && fiber.dom !== null) {
    updateDom(fiber.dom, fiber.base.props, fiber.props)
  }
  commitWorker(fiber.child)
  commitWorker(fiber.sibling)
}

function commitDeletion (fiber, domParent) {
  if (fiber.dom) {
    domParent.removeChild(fiber.dom)
  } else {
    commitDeletion(fiber.child, domParent)
  }
}

let wipRoot = null
// 下一个单元任务
let nextUnitOfWork = null
let currentRoot = null
let deletions = null

// 调度diff或者渲染任务
function workLoop (deadline) {
  while (nextUnitOfWork && deadline.timeRemaining() > 1) {
    // 存在下一个任务 且当前帧还没有结束
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
  }

  // 没有下一个任务 且 根节点还在
  if (!nextUnitOfWork && wipRoot) {
    commitRoot()
  }

  requestIdleCallback(workLoop)
}

function performUnitOfWork (fiber) {

  if (!fiber.dom) {
    // 不是入口
    fiber.dom = createDom(fiber)
  }

  // if (fiber.parent) {
  //   fiber.parent.dom.appendChild(fiber.dom)
  // }
  reconcileChildren(fiber, fiber.props.children)

  // 找下一个任务 先找子元素
  if (fiber.child) {
    return fiber.child
  }

  // 没有子元素 找兄弟元素
  let nextFiber = fiber
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling
    }
    // 没有兄弟元素 找父元素
    nextFiber = nextFiber.parent
  }
}

function reconcileChildren (wipFiber, elements) {
  // 构建fiber
  let index = 0
  let oldFiber = wipFiber.base && wipFiber.base.child
  let preSibling = null

  while (index < elements.length) {
    let element = elements[index]
    let newFiber = null
    const sameType = oldFiber && element && oldFiber.type === element.type
    // 复用节点
    if (sameType) {
      newFiber = {
        type: oldFiber.type,
        props: element.props,
        dom: oldFiber.dom,
        parent: wipFiber,
        base: oldFiber,
        effectTag: "UPDATE",
      }
    }

    //新增节点
    if (!sameType && element) {
      newFiber = {
        type: element.type,
        props: element.props,
        dom: null,
        parent: wipFiber,
        base: null,
        effectTag: "PLACEMENT",
      }
    }

    // 删除节点
    if (!sameType && oldFiber) {
      oldFiber.effectTag = "DELETION"
      deletions.push(oldFiber)
    }

    if (oldFiber) {
      oldFiber = oldFiber.sibling
    }

    if (index === 0) {
      // 第一个元素，是父 fiber 的 child 属性
      wipFiber.child = newFiber
    } else {
      // 其他元素是兄弟元素
      preSibling.sibling = newFiber
    }
    preSibling = newFiber
    index++
  }
}

requestIdleCallback(workLoop)

export default {
  createElement,
  render
}